package com.gin.kotlin.no_gay_alliance.worker

import android.content.Context
import android.util.Log
import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkRequest
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.gin.kotlin.no_gay_alliance.app.App
import com.gin.kotlin.no_gay_alliance.argument.ReplyListArgument
import com.gin.kotlin.no_gay_alliance.database.entity.ReplyHistoryTask.Status
import com.gin.kotlin.no_gay_alliance.database.entity.ReplyHistoryTask.Type
import com.gin.kotlin.no_gay_alliance.database.entity.ReplyHistoryTaskLog
import com.gin.kotlin.no_gay_alliance.provider.ngaphp.ReplyListProvider
import java.io.InterruptedIOException
import java.net.SocketException
import java.net.UnknownHostException
import java.time.ZonedDateTime
import java.util.concurrent.TimeUnit

/**
 * 回复历史，扫描类任务
 * @constructor
 */
class ReplyHistoryTaskScannerWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    private val dao = App.INSTANCE.database.replyHistoryTaskDao()
    private val logDao = App.INSTANCE.database.replyHistoryTaskLogDao()

    override fun doWork(): Result {
        val list = dao.list()
            ?.filter { it.type == Type.SCANNER }
            ?: return success()

        // 从列表中获取任务，优先级： 进行中任务 > 等待中任务
        val task =
            // 第一个进行中任务
            list.firstOrNull { it.status == Status.IN_PROCESS }
            // 第一个等待中任务
                ?: list.firstOrNull { it.status == Status.WAITING }?.also { it.status = Status.IN_PROCESS }
                ?: return success()

        Log.i(TAG, "回复历史任务 - 自动扫描")

        // 当前请求的目标页
        val page = task.currentPage.takeIf { it > 0 } ?: task.start

        try {
            val body = ReplyListProvider.getInstance().execute(ReplyListArgument(ReplyListArgument.Type.LIST, topicId = task.topicId, page = page, html = true), ignoreCache = true)

            // 如果任务结束，修改状态，如果未结束则进度+1
            val completed = page == task.end
            task.status = if (completed) Status.COMPLETED else task.status
            task.currentPage = if (completed) task.currentPage else page + 1
            task.totalPage = body.totalPage ?: task.totalPage
            task.updatedTime = ZonedDateTime.now()
            dao.update(task)

            // 记录日志
            val msg = if (completed) "，任务已完成" else ""
            val log = ReplyHistoryTaskLog(id = 0, taskId = task.id, code = 200, message = "第 $page 页，请求成功$msg", timestamp = ZonedDateTime.now())
            logDao.add(log)
        } catch (e: Exception) {
            val msg = "${e.javaClass.simpleName}: ${e.localizedMessage}"
            var log = ReplyHistoryTaskLog(taskId = task.id)
            val warnMessage = "第 $page 页，请求异常，即将重试: $msg"
            when (e) {
                is InterruptedIOException -> log = log.copy(code = 401, message = warnMessage)
                is UnknownHostException -> log = log.copy(code = 401, message = warnMessage)
                is SocketException -> log = log.copy(code = 401, message = warnMessage)
                else -> {
                    log = log.copy(code = 400, message = "第 $page 页，请求失败，任务已停止: $msg")
                    dao.setStatus(task.id, Status.ERROR)
                    e.printStackTrace()
                }
            }
            logDao.add(log)
            return success(DELAY_SECONDS * 4)
        }


        return success()
    }

    private fun success(delaySeconds: Long = DELAY_SECONDS): Result {
        start(delaySeconds)
        return Result.success()
    }


    companion object {
        /**
         * 默认的延迟秒数
         */
        const val DELAY_SECONDS = 15L
        private val TAG = ReplyHistoryTaskScannerWorker::class.java.simpleName

        @JvmStatic
        fun start(delaySeconds: Long = DELAY_SECONDS) {
            val manager = WorkManager.getInstance(App.INSTANCE)
            // 清空相同任务
            manager.cancelAllWorkByTag(ReplyHistoryTaskScannerWorker::class.java.name)
            // 构造任务请求
            // 任务限制：必须联网
            val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
            // 一次性任务
            val workRequest = OneTimeWorkRequest.Builder(ReplyHistoryTaskScannerWorker::class.java)
                .setConstraints(constraints)
                // 执行延迟
                .setInitialDelay(delaySeconds, TimeUnit.SECONDS)
                // 重试策略
                .setBackoffCriteria(BackoffPolicy.LINEAR, WorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS)
                .build()
            // 提交任务
            manager.enqueue(workRequest)
        }

    }

}